using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using miciv;
using micivCore.Data;
using micivCore.Player;

namespace micivCore.Components
{
    public class CoUnitProto : ComponentPrototypeBase<CoUnitManager>
    {
        #region Properties

        protected uint m_uCreateSpeed;
        public uint CreateSpeed
        {
            get
            {
                return this.m_uCreateSpeed;
            }
        }

        protected bool m_bIsGroundType;
        public bool IsGroundType
        {
            get
            {
                return this.m_bIsGroundType;
            }
        }

        protected bool m_bIsWaterType;
        public bool IsWaterType
        {
            get
            {
                return this.m_bIsWaterType;
            }
        }

        protected bool m_bIsAirType;
        public bool IsAirType
        {
            get
            {
                return this.m_bIsAirType;
            }
        }

        protected float m_fLife;
        public float Life
        {
            get
            {
                return this.m_fLife;
            }
        }

        protected uint m_uRadiusOfInfluence;
        public uint RadiusOfInfluence
        {
            get
            {
                return this.m_uRadiusOfInfluence;
            }
        }

        #endregion

        protected Hashtable m_htblTechniques;
        protected List<IUnitTechnique> m_lstTechniques;
        public List<IUnitTechnique> Techniques
        {
            get
            {
                return this.m_lstTechniques;
            }
        }

        public CoUnitProto()
        {
            this.m_uCreateSpeed = 1;
            this.m_bIsGroundType = true;
            this.m_bIsWaterType = false;
            this.m_bIsAirType = false;
            this.m_fLife = 1.0f;
            this.m_uRadiusOfInfluence = 1;
            this.m_htblTechniques = new Hashtable();
            this.m_lstTechniques = new List<IUnitTechnique>();
        }

        override public bool Initialize(EntityPrototype _enProto, XmlElement _xmlConfig, IComponentManager _coManager)
        {
            if (false != base.Initialize(_enProto, _xmlConfig, _coManager))
            {
                CoreManager coreManager = this.Manager.CoreContext.CoreManager;
                this.m_uCreateSpeed = uint.Parse(coreManager.GetXmlAttributeValue(_xmlConfig, "createspeed", "1"));
                this.m_bIsGroundType = bool.Parse(coreManager.GetXmlAttributeValue(_xmlConfig, "isgroundtype", "true"));
                this.m_bIsWaterType = bool.Parse(coreManager.GetXmlAttributeValue(_xmlConfig, "iswatertype", "false"));
                this.m_bIsAirType = bool.Parse(coreManager.GetXmlAttributeValue(_xmlConfig, "isairtype", "false"));
                this.m_fLife = float.Parse(coreManager.GetXmlAttributeValue(_xmlConfig, "life", "1.0"));
                this.m_uRadiusOfInfluence = uint.Parse(coreManager.GetXmlAttributeValue(_xmlConfig, "radiusofinfluence", "1"));
                this.InitializeTechniques(_xmlConfig.SelectSingleNode("techniques") as XmlElement);
                return true;
            }
            return false;
        }

        protected void InitializeTechniques(XmlElement _xmlTechniques)
        {
            foreach (XmlNode xmlChild in _xmlTechniques.ChildNodes)
            {
                XmlElement xmlTechnique = xmlChild as XmlElement;
                if (null != xmlTechnique)
                {
                    IUnitTechnique technique = this.m_coManager.CreateTechnique(xmlTechnique);
                    if (null == technique)
                    {
                        throw new Exception(string.Format("could not create {0} {1} technique", xmlTechnique.Attributes["id"].Value, xmlTechnique.Name));
                    }
                    if (false != this.m_htblTechniques.ContainsKey(technique.ID))
                    {
                        throw new Exception(string.Format("could not create {0} technique is already declared in {1} unit", technique.ID, this.ID));
                    }
                    this.m_htblTechniques.Add(technique.ID, technique);
                    this.m_lstTechniques.Add(technique);
                }
            }
        }
    }

    public class CoUnit : Level.LevelComponentBase<CoUnitProto>, IUnit
    {
        protected CoCompositeRenderable m_coCompositeRenderable;
        protected MapTile m_mapTile;
        protected IPlayer m_owner;

        public CoUnit()
        {

        }

        override public bool Initialize(Entity _entity, IComponentPrototype _coProto)
        {
            if (false != base.Initialize(_entity, _coProto))
            {
                return true;
            }
            return false;
        }

        override public void PostInitialize(XmlElement _xmlComponent)
        {
            base.PostInitialize(_xmlComponent);
            this.CoreContext.GetData<UnitManager>("UnitManager").Add(this.ID, this);
            this.m_coCompositeRenderable = this.Entity.GetComponentByType<CoCompositeRenderable>();
            if (null != _xmlComponent)
            {
                XmlNodeList xmlStates = _xmlComponent.SelectNodes("state");
                foreach (XmlElement xmlState in xmlStates)
                {
                    switch (xmlState.Attributes["id"].Value)
                    {
                        case "mapcoordinates":
                            MapCoords mapCoord = new MapCoords();
                            mapCoord.X = uint.Parse(this.CoreManager.GetXmlAttributeValue(xmlState, "x", "0"));
                            mapCoord.Y = uint.Parse(this.CoreManager.GetXmlAttributeValue(xmlState, "y", "0"));
                            this.m_coCompositeRenderable.SetMapCoord(mapCoord);
                            this.Level.MapCommunicator.AttachUnitToMapTile(mapCoord, this);
                            break;
                        case "ownerindex":
                            int ownerIndex = int.Parse(this.CoreManager.GetXmlAttributeValue(xmlState, "value", "0"));
                            this.Owner = this.Level.GetPlayer(ownerIndex);
                            break;
                    }
                }
            }
        }

        #region IUnit Members

        public IPlayer Owner
        {
            get
            {
                return this.m_owner;
            }
            set
            {
                this.m_owner = value;
            }
        }

        public MapTile MapTile
        {
            get
            {
                return this.m_mapTile;
            }
            set
            {
                this.m_mapTile = value;
            }
        }

        public List<IUnitTechnique> Techniques
        {
            get
            {
                return this.m_coProto.Techniques;
            }
        }

        #endregion
    }
}
